package com.sf.bank.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 代码尽量写注释，写不明白也写，写多就会写了
 * 反射，¥500-¥2000
 */
public class RefectionTest01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, SecurityException {
        /*
         * 如果调用的是static的方法或者字段，则无需实例化，不要c1.newInstance();因为静态方法是在构造器之前执行
         */
        //声明class对象
        Class c1 = Class.forName("com.sf.bank.reflection.UserInfo");

        //声明有参构造，有参构造器需要实例化前声明构造器，无参构造不需要声明构造器对象
        Constructor con1 = c1.getConstructor(String.class,String.class,int.class);
        //通过有参构造实例化UserInfo 等同 new UserInfo("w","w",1);
        Object o1 = con1.newInstance("w","w",1);

        System.out.println("===============================");
        //声明class对象
        Class c2 = Class.forName("com.sf.bank.reflection.MethodInvokeTest");
        //实例化无参构造直接用newInstance();
        Object object = c2.newInstance();
        //声明public方法用getMethod
        Method m2 = c2.getMethod("test01",String.class);
        m2.invoke(object,"susu");

        System.out.println("===============================");
        //声明private方法用getDeclaredMethod
        Method m3 = c2.getDeclaredMethod("test02");
        //调用私有方法前需要关闭权限检查
        m3.setAccessible(true);
        //调用无参方法,只需要一个参数，就是类的实例化
        //m3.invoke(c2.newInstance());,因为调用的是构造器，属于方法，所以需要invoke调用
        m3.invoke(object);

        System.out.println("===============================");
        //声明private带参数的私有方法
        Method m4 = c2.getDeclaredMethod("test03",String.class,int.class);
        //调用私有方法前需要关闭权限检查
        m4.setAccessible(true);
        //调用无参方法,第一个参数为类实例化，之后的参数为test03方法的几个参数，有几个写几个
        m4.invoke(object,"参数str",2);

        System.out.println("===============================");
        //注意，调用包含有参构造器，需要把默认的无参构造器声明，不然报错，不知道调用哪个构造器
        //或者指定有参构造器
        //1.无参构造
        UserInfo userInfo = (UserInfo)c1.newInstance();
        Field f1 = c1.getDeclaredField("id");
        f1.setAccessible(true);
        f1.set(userInfo,"o001");
        System.out.println(userInfo.getId());
        System.out.println("===============================");
        //2.有参构造
        Constructor con2 = c1.getConstructor(String.class,String.class,int.class);
        UserInfo userInfo2 = (UserInfo)con2.newInstance("u1","u2",3);
        Field f2 = c1.getDeclaredField("id");
        f2.setAccessible(true);
        f2.set(userInfo2,"o002");
        System.out.println(userInfo2.getId());

        //调用父类

        //反射实现借口，调用借口的方法

        //调用static属性和方法



    }
}

/**
 * 实际开发中不要在类里面写类
 */
class MethodInvokeTest{
    private int i;
    public void test01(String str){
        System.out.println("参数："+str);
    }
    private void test02(){
        System.out.println("无参私有方法");
    }
    private void test03(String str,int i){
        System.out.println("有参私有方法"+i+str);
    }
}
